package serialapi

import (
	"encoding/hex"
	"encoding/json"
	"fmt"
	"io"
	"iot-base/common/serialdata"
	"iot-base/common/webapi"
	"net"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/tarm/serial"
)

type serialRequest struct {
	Mod      string `json:"mod"`
	Ip       string `json:"ip"`
	Port     string `json:"port"`
	Name     string `json:"serialName"`
	Baud     string `json:"baud"`
	Databit  string `json:"databit"`
	Stop     string `json:"stop"`
	Check    string `json:"check"`
	Hex      bool   `json:"hex"`
	SendData string `json:"sendData"`
}

func InitSerialApi(r *gin.RouterGroup) {
	serialApi := r.Group("/serial")
	{
		serialApi.POST("", func(c *gin.Context) {
			dataFrame := serialdata.DataFrame{}
			var request serialRequest
			err := c.BindJSON(&request)
			if err != nil {
				webapi.SendError("json marshal err:"+err.Error(), webapi.ParamsError, c)
				return
			}
			dataFrame.Style = "serve"
			mod := request.Mod
			data := request.SendData
			ishex := request.Hex
			if ishex {
				arr := strings.Split(strings.Trim(data, `\n`), " ")
				var res = make([]byte, len(arr))
				for n, v := range arr {
					h, err := strconv.ParseInt(v, 16, 16)
					if err != nil {
						fmt.Println(err)
					}
					res[n] = byte(h)
				}
				res = res[:len(arr)]
				if err != nil {
					webapi.SendError("parse hex err:"+err.Error(), webapi.ExecError, c)
				}
				dataFrame.Value = res
			} else {
				dataFrame.Value = []byte(data)
			}
			switch mod {
			case "本机串口":
				name := request.Name
				baud := request.Baud
				b, _ := strconv.ParseInt(baud, 10, 16)
				databit := request.Databit
				d, _ := strconv.ParseInt(databit, 10, 16)
				stop := request.Stop
				check := request.Check
				dataFrame.Mod = "serial"
				dataFrame.Config = serial.Config{
					Name:        name,
					Baud:        int(b),
					Size:        byte(d),
					ReadTimeout: 1000,
					Parity:      ParseParity(check),
					StopBits:    ParseStop(stop),
				}
			case "串口服务器":
				ip := request.Ip
				port := request.Port
				dataFrame.Mod = "tcp"
				dataFrame.Addr = ip + ":" + port
			}
			conn, err := net.Dial("tcp", serialdata.SerialIP)
			if err != nil {
				webapi.SendError("conn err:"+err.Error(), webapi.ExecError, c)
				return
			}
			buff, err := json.Marshal(dataFrame)
			if err != nil {
				webapi.SendError("json marshal err:"+err.Error(), webapi.ExecError, c)
				return
			}
			_, err = conn.Write(buff)
			if err != nil {
				webapi.SendError("conn write err:"+err.Error(), webapi.ExecError, c)
				return
			}
			var resbuff = make([]byte, 2048)
			n, err := io.ReadAtLeast(conn, resbuff, 4)
			if err != nil {
				webapi.SendError("conn read err:"+err.Error(), webapi.ExecError, c)
				return
			}
			fmt.Println("res:", resbuff[:n])
			if ishex {
				var tmp string
				for _, v := range resbuff[:n] {
					tmp += fmt.Sprintf("%v ", hex.EncodeToString([]byte{v}))
				}
				webapi.SendResult(gin.H{"result": tmp}, nil, c)
			} else {
				webapi.SendResult(gin.H{"result": string(resbuff[:n])}, nil, c)
			}
		})
	}
}

func ParseParity(str string) serial.Parity {
	switch strings.ToUpper(str) {
	case "N":
		return serial.ParityNone
	case "O":
		return serial.ParityOdd
	case "E":
		return serial.ParityEven
	case "M":
		return serial.ParityMark
	case "S":
		return serial.ParitySpace
	default:
		return serial.ParityNone
	}
}

func ParseStop(str string) serial.StopBits {
	switch str {
	case "1":
		return serial.Stop1
	case "1.5":
		return serial.Stop1Half
	case "2":
		return serial.Stop2
	default:
		return serial.Stop1
	}
}
